#include "wm8978.hpp"
#include "i2c.h"
#include "sai.h"

static void writeReg(uint8_t reg, uint16_t val)
{
    reg = (reg << 1) | ((val >> 8) & 0X01);
    uint8_t data = val & 0XFF;

    // HAL_I2C_Mem_Write(&hi2c2, (0X1A << 1) | 0, reg, I2C_MEMADD_SIZE_8BIT, &data, 1, 0xFFFF);
    HAL_I2C_Mem_Write(&hi2c2, 0x34, reg, I2C_MEMADD_SIZE_8BIT, &data, 1, 0xFFFF);
}

void setVolume(uint8_t beep, uint8_t voll, uint8_t volr)
{
    beep &= 0X3F; // 限定范围
    if (beep == 0)
        beep |= 1 << 6;            // 音量为0时, 直接mute
    writeReg(54, beep);            // R54, 喇叭左声道音量设置
    writeReg(55, beep | (1 << 8)); // R55, 喇叭右声道音量设置,同步更新(SPKVU=1)

    voll &= 0X3F;
    volr &= 0X3F; // 限定范围
    if (voll == 0)
        voll |= 1 << 6; // 音量为 0 时, 直接 mute
    if (volr == 0)
        volr |= 1 << 6;            // 音量为 0 时,直接 mute
    writeReg(52, voll);            // R52, 耳机左声道音量设置
    writeReg(53, volr | (1 << 8)); // R53, 耳机右声道音量设置, 同步更新(HPVU=1)
}

void wmInit()
{
    writeReg(0, 0);
    writeReg(1, 0X1B);    // R1,MICEN设置为1(MIC使能),BIASEN设置为1(模拟器工作),VMIDSEL[1:0]设置为:11(5K)
    writeReg(2, 0X1B0);   // R2,ROUT1,LOUT1输出使能(耳机可以工作),BOOSTENR,BOOSTENL使能
    writeReg(3, 0X6F);    // R3,LOUT2,ROUT2输出使能(喇叭工作),RMIX,LMIX使能
    writeReg(4, (2 << 3));
    writeReg(6, 0);       // R6,MCLK由外部提供
    writeReg(10, 1 << 3); // R10,SOFTMUTE关闭,128x采样,最佳SNR
    writeReg(14, 1 << 3); // R14,ADC 128x采样率
    writeReg(43, 1 << 4); // R43,INVROUT2反向,驱动喇叭
    writeReg(47, 1 << 8); // R47设置,PGABOOSTL,左通道MIC获得20倍增益
    writeReg(48, 1 << 8); // R48设置,PGABOOSTR,右通道MIC获得20倍增益
    writeReg(49, 1 << 1 | 1 << 2); // R49,TSDEN,开启过热保护
    writeReg(50, 1);      // R50设置
    writeReg(51, 1);      // R51设置
}

void setBeepVolume(uint8_t volumn)
{
    // 范围 [5:0] 第 6 位写 1 表示 mute
    volumn = volumn ? volumn & 0X3F : 1 << 6;
    writeReg(54, volumn);
    writeReg(55, volumn | (1 << 8));
}

void setPhoneVolume(uint8_t volumn)
{
    volumn = volumn ? volumn & 0X3F : 1 << 6;
    writeReg(52, volumn);
    writeReg(53, volumn | (1 << 8));
}

// SAI Block A采样率设置
// 采样率计算公式:
// MCKDIV != 0: Fs=SAI_CK_x/[512*MCKDIV]
// MCKDIV == 0: Fs=SAI_CK_x/256
// SAI_CK_x = (HSE/pllm)*PLLSAIN/PLLSAIQ/(PLLSAIDivQ+1)
// 一般 HSE = 25Mhz
// pllm:在 Stm32_Clock_Init 设置的时候确定, 一般是25
// PLLSAIN: 一般是50~432 
// PLLSAIQ: 2~15 
// PLLSAIDivQ: 1~32
// MCKDIV: 0~15 
// SAI A分频系数表 @pllm=25,HSE=25Mhz, 即 vco 输入频率为 1Mhz 
const uint16_t SAI_PSC_TBL[][5]= {
    {800  , 344, 7, 1 , 12},	// 8        Khz
    {1102 , 429, 2, 19, 2},     // 11.025   Khz
    {1600 , 344, 7,  1, 6},     // 16       Khz
    {2205 , 429, 2, 19, 1},     // 22.05    Khz
    {3200 , 344, 7,  1, 3},     // 32       Khz
    {4410 , 429, 2, 19, 0},     // 44.1     Khz
    {4800 , 344, 7,  1, 2},     // 48       Khz
    {8820 , 271, 2,  3, 1},     // 88.2     Khz
    {9600 , 344, 7,  1, 1},     // 96       Khz
    {17640, 271, 2,  3, 0},     // 176.4    Khz
    {19200, 344, 7,  1, 0},     // 192      Khz
};

//设置SAIA的采样率(@MCKEN)
//samplerate:采样率,单位:Hz
//返回值:0,设置成功;1,无法设置.
uint8_t SAIA_SampleRate_Set(uint32_t samplerate)
{   
    uint8_t i = 0;
    
    for (i = 0; i < sizeof(SAI_PSC_TBL) / 10; i++) {
        if ((samplerate / 10) == SAI_PSC_TBL[i][0]) break;
    }

    if (i == sizeof(SAI_PSC_TBL) / 10) return 1;  // 搜遍了也找不到

    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
    PeriphClkInitStruct.PLLI2S.PLLI2SN = (uint32_t)SAI_PSC_TBL[i][1]; 
    PeriphClkInitStruct.PLLI2S.PLLI2SP = RCC_PLLP_DIV2;
    PeriphClkInitStruct.PLLI2S.PLLI2SR = (uint32_t)SAI_PSC_TBL[i][4];
    PeriphClkInitStruct.PLLI2S.PLLI2SQ = (uint32_t)SAI_PSC_TBL[i][2];
    PeriphClkInitStruct.PLLI2SDivQ = (uint32_t)SAI_PSC_TBL[i][3];
    PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLI2S;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
    
    hsai_BlockA1.Init.AudioFrequency = samplerate;           // 设置频率

    HAL_SAI_Init(&hsai_BlockA1);

    return 0;
} 
